#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 初始化，读取摄像头信息
    dev_list = getDeviceList();
    for(int i=0; i<dev_list.length(); i++)
    {
        QString device_name = getDeviceName(&dev_list, i);
        ui->comboBox_device_name->addItem(device_name);
    }
    connect(ui->comboBox_device_name, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeDevice(int)));


    dev = new QCamera(dev_list.at(0));           // 创建设备
    video = new QVideoProbe;                     // 创建视频
    if(video != nullptr)
    {
        video->setSource(dev);
        connect(video, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(slotOnProbeFrame(QVideoFrame)), Qt::QueuedConnection);
    }
    dev->setCaptureMode(QCamera::CaptureViewfinder);    // 设置捕捉模式为视频,CaptureViewfinder,CaptureVideo,CaptureStillImage


    // 获取分辨率列表
    resolution_list = getResolutionList(dev);
    for (int i=0; i< resolution_list.length(); i++)
    {
        QString resolution_string = getResolutionQString(&resolution_list, i);
        ui->comboBox_resolution->addItem(resolution_string);
    }
    connect(ui->comboBox_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeResolution(int)));

    // 获取摄像头帧率
    QList<QCamera::FrameRateRange> frameRate = dev->supportedViewfinderFrameRateRanges();
    foreach (auto i, frameRate)
    {
        qDebug() << i.maximumFrameRate;
    }

    // 获取摄像头支持视频格式
    QList<QVideoFrame::PixelFormat> pixelFormat = dev->supportedViewfinderPixelFormats();
    foreach (auto i, pixelFormat)
    {
        qDebug() << i;
    }

    // 设置分辨率 & 帧率 (不能同时设置最大帧率和最小帧率，会报错)
    /*
    QCameraViewfinderSettings set;
    set.setResolution(resolution.at(0));
    set.setMinimumFrameRate(5.0);
    set.setPixelFormat(QVideoFrame::Format_Jpeg);
    dev->setViewfinderSettings(set);
    dev->start();
    */
    m_resolution_width = getResolutionWidth(&resolution_list, 0);
    m_resolution_height = getResolutionHeight(&resolution_list, 0);

    QCameraViewfinderSettings set = dev->viewfinderSettings();
    set.setResolution(resolution_list.at(0));
    dev->setViewfinderSettings(set);
    dev->start();

    // 信号槽
    connect(ui->btn_zoom_in, &QPushButton::clicked, this, &Widget::slot_zoom_in);
    connect(ui->btn_zoom_out, &QPushButton::clicked, this, &Widget::slot_zoom_out);
    connect(ui->btn_rotate, &QPushButton::clicked, this, &Widget::slot_rotate);
    connect(ui->check_horizontal, SIGNAL(stateChanged(int)), this, SLOT(slot_horizontal(int)));
    connect(ui->check_vertical, SIGNAL(stateChanged(int)), this, SLOT(slot_vertical(int)));
    connect(ui->check_crop, SIGNAL(stateChanged(int)), this, SLOT(slot_crop(int)));
    connect(ui->btn_scan, &QPushButton::clicked, this, &Widget::slot_scan);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::slotOnProbeFrame(const QVideoFrame &frame)
{
    //qDebug() << "获取到视频帧";

    QVideoFrame cframe(frame);
    cframe.map(QAbstractVideoBuffer::ReadOnly);

    // Windows上可以直接 QImage::fromData,但是Mac上跑不起来，所以需要做下判断
    QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(cframe.pixelFormat());
    if (imageFormat != QImage::Format_Invalid)
    {
        m_img = QImage(cframe.bits(), cframe.width(), cframe.height(), imageFormat);
    }
    else
    {
        m_img = QImage::fromData(cframe.bits(), cframe.mappedBytes());
    }
    cframe.unmap();

    // 旋转
    QMatrix matrix;
    switch (m_rotate) {
        case 1:{matrix.rotate(90);}break;
        case 2:{matrix.rotate(180);}break;
        case 3:{matrix.rotate(270);}break;
    }
    m_img = m_img.transformed(matrix);

    // 镜像
    m_img = m_img.mirrored(m_horizontal, m_vertical);

    // 缩放,数字记得写真实的分辨率
    QRect rect = QRect(m_resolution_width*(m_scaled-1)/2,
                       m_resolution_height*(m_scaled-1)/2,
                       m_resolution_width-m_resolution_width*(m_scaled-1),
                       m_resolution_height-m_resolution_height*(m_scaled-1));
    m_img = m_img.copy(rect);
}

void Widget::slotChangeDevice(int index)
{
    dev->stop();
    delete dev;
    dev = new QCamera(dev_list.at(index));
    video->setSource(dev);

    disconnect(ui->comboBox_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeResolution(int)));
    ui->comboBox_resolution->clear();
    resolution_list.clear();
    resolution_list = getResolutionList(dev);
    for (int i=0; i<resolution_list.length(); i++)
    {
        QString resolution_string = getResolutionQString(&resolution_list, i);
        ui->comboBox_resolution->addItem(resolution_string);
    }
    connect(ui->comboBox_resolution, SIGNAL(currentIndexChanged(int)), this, SLOT(slotChangeResolution(int)));

    m_resolution_width = getResolutionWidth(&resolution_list, 0);
    m_resolution_height = getResolutionHeight(&resolution_list, 0);
    dev->start();
}

void Widget::slotChangeResolution(int index)
{
    dev->stop();
    delete dev;
    int dev_index = ui->comboBox_device_name->currentIndex();
    dev = new QCamera(dev_list.at(dev_index));
    video->setSource(dev);

    dev->load();
    QCameraViewfinderSettings set = dev->viewfinderSettings();
    set.setResolution(resolution_list.at(index));
    dev->setViewfinderSettings(set);

    m_resolution_width = getResolutionWidth(&resolution_list, index);
    m_resolution_height = getResolutionHeight(&resolution_list, index);
    dev->start();
}

void Widget::slot_zoom_in()
{
    if (m_scaled < 1.9){m_scaled+=0.1;}else{m_scaled=1.9;}
    qDebug() << "放大, scaled:" << m_scaled;
}

void Widget::slot_zoom_out()
{
    if(m_scaled>1.1){m_scaled-=0.1;}else{m_scaled=1.0;}
    qDebug() << "缩小, scaled:" << m_scaled;
}

void Widget::slot_rotate()
{
    if (m_rotate < 3){m_rotate += 1;}else{m_rotate = 0;}
}

void Widget::slot_horizontal(int)
{
    if(ui->check_horizontal->checkState() == Qt::Checked)
    {
        m_horizontal = true;
    }
    else
    {
        m_horizontal = false;
    }
}

void Widget::slot_vertical(int)
{
    if(ui->check_vertical->checkState() == Qt::Checked)
    {
        m_vertical = true;
    }
    else
    {
        m_vertical = false;
    }
}

void Widget::slot_crop(int)
{
    if(ui->check_crop->checkState() == Qt::Checked)
    {
        m_kuangxuan_state = true;
    }
    else
    {
        m_kuangxuan_state = false;
        m_kuangxuan = QRect();
    }
}

void Widget::slot_scan()
{
    if (m_kuangxuan_state)
    {
        // 框选拍照
        QRect r2 = ui->widget->geometry();
        QRect r3;
        double b = m_img.width() / r2.width();
        double x = (m_kuangxuan.x() - r2.x()) > 0 ? (m_kuangxuan.x() - r2.x()) * b : 0;
        double y = (m_kuangxuan.y() - r2.y()) > 0 ? (m_kuangxuan.y() - r2.y()) * b : 0;
        r3.setX(x);
        r3.setY(y);
        r3.setWidth((m_kuangxuan.width() + (m_kuangxuan.x() - r2.x())) * b);
        r3.setHeight((m_kuangxuan.height() + (m_kuangxuan.y() - r2.y())) * b);
        m_img.copy(r3).save("scan.jpg");

    }
    else{m_img.save("scan.jpg");}
    qDebug() << "拍照：scan.jpg QImage width:" << m_img.width() << " height:" << m_img.height();
}

void Widget::paintEvent(QPaintEvent* e)
{
    QPainter p(this);
    p.setPen(Qt::red);
    p.drawImage(ui->widget->geometry(), m_img);
    if (m_kuangxuan_state){p.drawRect(m_kuangxuan);}
    update();
}

void Widget::mousePressEvent(QMouseEvent* e)
{
    if (ui->widget->geometry().contains(e->pos()) && e->button() == Qt::LeftButton && m_kuangxuan_state == true)
    {
        m_kuangxuan = QRect(e->pos().x(), e->pos().y(), 0,0);
        m_kuangxuan.setX(e->pos().x());
        m_kuangxuan.setY(e->pos().y());
    }
}

void Widget::mouseReleaseEvent(QMouseEvent* e)
{
    if (ui->widget->geometry().contains(e->pos()) && e->button() == Qt::LeftButton && m_kuangxuan_state == true)
    {
        m_kuangxuan.setWidth(e->pos().x() - m_kuangxuan.x());
        m_kuangxuan.setHeight(e->pos().y() - m_kuangxuan.y());
        qDebug() << "kuangxuan rect:" << m_kuangxuan;
    }
}




// **************************** 下面是封装的方法 **************************************************************************************

// 获取摄像头列表
QList<QCameraInfo> Widget::getDeviceList()
{
    return QCameraInfo::availableCameras();
}

// 获取摄像头完整信息
QString Widget::getDeviceFullInfo(QList<QCameraInfo> *device_list, int device_index)
{
    return device_list->at(device_index).deviceName();
}

// 获取摄像头名称
QString Widget::getDeviceName(QList<QCameraInfo> *device_list, int device_index)
{
    return device_list->at(device_index).description();
}

// 获取分辨率列表（降序）
QList<QSize> Widget::getResolutionList(QCamera *device)
{
    device->load();
    QList<QSize> resolution_old = device->supportedViewfinderResolutions();
    QList<QSize> resolution_new = {};
    while(!resolution_old.isEmpty())
    {
        resolution_new.append(resolution_old.takeLast());
    }
    return resolution_new;
}

// 获取分辨率宽度
int Widget::getResolutionWidth(QList<QSize> *resolution_list, int index)
{
    return resolution_list->at(index).width();
}

// 获取分辨率高度
int Widget::getResolutionHeight(QList<QSize> *resolution_list, int index)
{
    return resolution_list->at(index).height();
}

// 获取分辨率字符串，例：“800x600”
QString Widget::getResolutionQString(QList<QSize> *resolution_list, int index, QString join)
{
    int width = resolution_list->at(index).width();
    int height = resolution_list->at(index).height();
    QString resolution_string = QString("%1%2%3").arg(width).arg(join).arg(height);
    return resolution_string;
}



